/** @file    JSpaceWrappers.cpp
 *  @author  Alessandro Polo
 *  @version $Id: JSpaceWrappers.cpp 2891 2010-08-12 01:58:59Z alex $
 *  @brief
 * File containing methods for the JSpaceWrappers class.
 * The header for this class can be found in JSpaceWrappers.h, check that file
 * for class description.
 ****************************************************************************/
/* Copyright (c) 2007-2010, WOSH - Wide Open Smart Home 
 * by Alessandro Polo - OpenSmartHome.com
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the OpenSmartHome.com WOSH nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY Alessandro Polo ''AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL Alessandro Polo BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ****************************************************************************/

 #include "JSpaceWrappers.h"
#include <unistd.h> // sleep

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

jsDisplayer::jsDisplayer() {
	this->dfb = NULL;
	this->events = NULL;

	this->layer = NULL;
	this->gwindow = NULL;
	this->gsurface = NULL;
	this->font = NULL;

	this->bOldY = 0;
	this->bOldH = WIN_H; 
	this->quit = 0;
	memset(this->fontname, 0, 128);
	memset(this->text, 0, 256);
 }

jsDisplayer::~jsDisplayer() {

 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

/*
bool jsDisplayer::waitForPlayer( unsigned long timeout, bool* optional_semaphore) {
	bool succeeded = false;
	while( true ) {
		succeeded = false;
		if ( optional_semaphore != NULL ) {
			if ( *optional_semaphore == false )
				break;
		 }
		sleep(1);
		DFBResult res = DirectFBCreate( &this->dfb );
		if ( res == DFB_OK ) {
			succeeded = true;
			break;
		 }
	 }
	return succeeded;
 }
*/
void jsDisplayer::initialize() {
	// Obtain the layer
	DFBCHECK( this->dfb->GetDisplayLayer(this->dfb, DLID_PRIMARY, &this->layer) );
	// Setup the Graphical window
	setupWindow();
	// Create event buffer and request focus
	DFBCHECK( this->gwindow->CreateEventBuffer( this->gwindow, &this->events ) );
	DFBCHECK( this->gwindow->SetOpacity( this->gwindow, 0xFF ) );
	DFBCHECK( this->gwindow->RequestFocus( this->gwindow ) ); 
	DFBCHECK( this->gsurface->Flip( this->gsurface, NULL, DSFLIP_NONE ) );
	// create font
	createFont();
	// initialize plasma background
	plasmaInit();
	// dunno?
	DFBCHECK( this->gsurface->SetFont(this->gsurface, this->font) );
	DFBCHECK( this->font->GetHeight(this->font, &this->th) );
	DFBCHECK( this->font->GetStringWidth(this->font, this->text, -1, &this->tw) );
 }

void jsDisplayer::enterLoop( bool* optional_semaphore ) {
	DFBWindowEvent event;
	// Event loop
	while ( !this->quit ) {
		if ( optional_semaphore != NULL ) {
			if ( *optional_semaphore == false )
				break;
		 }
		this->events->WaitForEventWithTimeout( this->events, 0, 2 ); 

		bY = (WIN_H-BAN_H) - ABS(fcos1[bAngle]);

		clearBG();

		rect.x = 0; rect.y = 0; rect.w = 0; rect.h = 0;
		// Below or Above
		if ( ( bY >= (bOldY+bOldH) ) || ( (bY+BAN_H) <= bOldY ) ) {
			rect.w = BAN_W;
			rect.y = bOldY;
			rect.h = bOldH;
		 }
		// Between
		else if ( ( bY >= bOldY ) && ( (bY+BAN_H) <= (bOldY+bOldH) ) ) {
			rect.w = BAN_W;
			rect.y = bOldY;
			rect.h = bOldH;
		 }
		// Overlapping Above
		else if ( (bY+BAN_H) < (bOldY+bOldH) ) {
			rect.w = BAN_W;
			rect.y = (bY+BAN_H);
			rect.h = (bOldY+bOldH)-(bY+BAN_H);
		 }
		// Overlapping Below
		else if ( bY > bOldY ) {
			rect.w = BAN_W;
			rect.y = bOldY;
			rect.h = (bY-bOldY);
		 }

		if ( rect.h ) 
			DFBCHECK( this->gsurface->FillRectangle( this->gsurface, rect.x, rect.y, rect.w, rect.h ) );

		update.x1 = rect.x;
		update.y1 = rect.y;
		update.x2 = rect.x + rect.w- 1;
		update.y2 = rect.y + rect.h- 1;

		bOldY = bY;
		bOldH = BAN_H;

		Plasma(bannerData, BAN_W, BAN_H, shades[0]);
		rect.x = 0;
		rect.y = bY;
		rect.w = BAN_W;
		rect.h = BAN_H-1;
		DFBCHECK( this->gsurface->Write( this->gsurface, &rect, (void *)bannerData, BAN_W*2 ));

		DFBCHECK( this->gsurface->SetColor (gsurface, 0xff, 0xff, 0xff,  0xff) ); // White
		DFBCHECK(this->gsurface->DrawString (gsurface,text, -1, (WIN_W-tw)/2, bY + (BAN_H-th)/2, DSTF_TOPLEFT ) );

		update.x1 = MIN(update.x1,0);
		update.y1 = MIN(update.y1,bY);
		update.x2 = MAX(update.x2,BAN_W - 1);
		update.y2 = MAX(update.y2,bY + BAN_H - 1);
		DFBCHECK(gsurface->Flip( gsurface, &update, DSFLIP_NONE ));

		bAngle += 2;
		bAngle &= 0xff;

		// Handle event
		while ( this->events->GetEvent( this->events, DFB_EVENT(&event) ) == DFB_OK ) {
			switch ( event.type ) {
				case DWET_KEYDOWN:
					switch (event.key_symbol) {
						case DIKS_SPACE:
						case DIKS_OK:
										quit = 1;
										break;
						default:
										break;
					 }
					break;
				case DWET_KEYUP:
				case DWET_POSITION:
				case DWET_SIZE:
				case DWET_CLOSE:
				case DWET_DESTROYED:
				case DWET_GOTFOCUS:
				case DWET_LOSTFOCUS:
				case DWET_BUTTONDOWN:
				case DWET_BUTTONUP:
				case DWET_MOTION:
				case DWET_ENTER:
				case DWET_LEAVE:
				case DWET_WHEEL:
				case DWET_POSITION_SIZE:
				case DWET_UPDATE:
				case DWET_NONE:
				case DWET_ALL:
				default:
					break;
			 }
		}
	 }
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

void jsDisplayer::setupWindow() {
	this->wdesc.flags  = (DFBWindowDescriptionFlags)( DWDESC_POSX | DWDESC_POSY | DWDESC_WIDTH | DWDESC_HEIGHT 
												| DWDESC_OPTIONS | DWDESC_PIXELFORMAT | DWDESC_STACKING);
	this->wdesc.posx   = 0;
	this->wdesc.posy   = 0;
	this->wdesc.width  = WIN_W;
	this->wdesc.height = WIN_H;
	//  this->wdesc.height = BAN_H;
	//  this->wdesc.pixelformat = DSPF_RGB16;
	this->wdesc.pixelformat = DSPF_ARGB4444;
	this->wdesc.stacking  = DWSC_MIDDLE;
	this->wdesc.options   = DWOP_NONE;
	DFBCHECK(this->layer->CreateWindow(layer, &wdesc, &gwindow));
	DFBCHECK(this->gwindow->GetSurface(gwindow, &gsurface));
	DFBCHECK(this->gsurface->Clear( gsurface, 0x00, 0x00, 0x00, 0x00 ));
	//  DFBCHECK(this->gwindow->SetColorKey(gwindow, 0x00, 0x00, 0x00));
 }
 
void jsDisplayer::clearBG() {
//	DFBCHECK( this->gsurface->Clear( this->gsurface, 0x00, 0x00, 0x00, 0x00 ) );
	// Clear background optimized:
	DFBCHECK( this->gsurface->SetColor(this->gsurface, 0x00, 0x00, 0x00,  0x00) );
 }

void jsDisplayer::createFont() {
	strncpy(this->fontname, DEFAULT_FNT, sizeof(this->fontname) );
	strncpy(this->text, "WOSH IS EVERYWHERE!", sizeof(this->text) );
	fontdesc.flags = (DFBFontDescriptionFlags)(DFDESC_HEIGHT | DFDESC_ATTRIBUTES); // BUGGY
	fontdesc.attributes = DFFA_NONE;
	fontdesc.height = 20;
	DFBCHECK( this->dfb->CreateFont(this->dfb, this->fontname, &this->fontdesc, &this->font) );
 }

void jsDisplayer::plasmaInit(){
	ColorRGB c0[4] = {127,0,255, 127,127,0, 127,255,0, 127,255,127};
	MakeColors(shades[0], c0[0], c0[1], 0, 159);
	MakeColors(shades[0], c0[1], c0[2], 160, 191);
	MakeColors(shades[0], c0[2], c0[0], 192, 255);
	for (int i=0; i<2048; i++) {
		fsin1[i] = sin(i/(2*5.0)) * 64 + 64;
		fsin2[i] = sin(i/(2*15.0)) * 64 + 64;
		fsin3[i] = sin(i/(2*35.0)) * 128 + 128;
	 }
	for (int i=0; i<256; i++) {
		fcos1[i] = cos((i*6.2832)/256)*(WIN_H-BAN_H);
	 }
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

